package com.capgemini.fs.presentation.forum.web.action;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;

import com.capgemini.fs.app.ekms.common.Constants;
import com.capgemini.fs.app.ekms.model.Forum;
import com.capgemini.fs.app.ekms.persistence.util.QueryHelper;
import com.capgemini.fs.app.ekms.service.ForumService;
import com.capgemini.fs.presentation.common.util.CommonMethods;
import com.capgemini.fs.presentation.forum.web.form.ModifyForumForm;

public class ModifyForumAction extends DispatchAction {

	private ForumService modifyForumService;
	private String oldForumName = null;
	//This "jsonObject" is used for store result message
	private JSONObject jsonObject = new JSONObject();
	private PrintWriter out = null;
	// Define page size as 10
	private int pageSize = 10;

	public ForumService getModifyForumService() {
		return modifyForumService;
	}

	public void setModifyForumService(ForumService modifyForumService) {
		this.modifyForumService = modifyForumService;
	}

	public ActionForward validate(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		String jsonString = CommonMethods.readJSONRequest(request);
		JSONObject jot = JSONObject.fromObject(jsonString);
		@SuppressWarnings("unused")
		String forumName = jot.getString("name");
		return null;
	}

	// Modify Forums
	public ActionForward modify(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		int errStatus = 0;
		HttpSession session = request.getSession();
		////////////WARNING!->topic name does not exist in session
		String topicName = (String) session.getAttribute("topicname");
		////////////WARNING!->topic name does not exist in session
		String errMessage = new String();
		String jsonString = CommonMethods.readJSONRequest(request);
		JSONObject jot = JSONObject.fromObject(jsonString);
		//Define JSONArray errors to transfer the error messages from server to page
		JSONArray errors = new JSONArray();
		Forum forum = serializeForum(jot);
		if (null == forum.getName().trim()
				|| "".equalsIgnoreCase(forum.getName().trim())) {
			errStatus = 1;
			errMessage = "Please fill in the mandatory field Forum Name!";
			request.setAttribute("Failed",
					"Please fill in the mandatory field Forum Name!");
			JSONObject jo = new JSONObject();
			jo.put("error", errMessage);
			errors.add(jo);
		}
		// Check whether there is a same group name in the existing database
		try {
			List<Forum> forumList = modifyForumService.getAllForums();
			for (Forum foruml : forumList) {
				if (forum.getName().trim().equalsIgnoreCase(
						this.oldForumName.trim())) {
					break;
				} else if (forum.getName().trim().equalsIgnoreCase(
						foruml.getName().trim())) {
					//Always remember transfer all the forums to page for displaying
					List<Forum> list = modifyForumService.getAllForums();
					request.setAttribute("forumList", list);
					errMessage = "The " + "\'" + forum.getName() + "\'"
							+ " already exist, please fill in again!";
					errStatus = 1;
					JSONObject jo = new JSONObject();
					jo.put("error", errMessage);
					errors.add(jo);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			//Always remember transfer all the forums to page for displaying
			List<Forum> list = modifyForumService.getAllForums();
			request.setAttribute("forumList", list);
			errMessage = "Modified failed!";
			errStatus = 1;
			JSONObject jo = new JSONObject();
			jo.put("error", errMessage);
			errors.add(jo);
		}

		// Active or Inactive Topics
		try {
			String isActiveOrInactiveTopics = jot
					.getString("isActiveOrInactiveTopic");
			int status = jot.getInt("status");
			if (status == Constants.FORUM_STATUS_ACTIVE) {
				if ("Active".equalsIgnoreCase(isActiveOrInactiveTopics)) {
					//WARNING!this method may not correct!
					modifyForumService.activeForumTopic(forum.getId(),
							topicName);
					//WARNING!this method may not correct!
				}
			} else if (status == Constants.FORUM_STATUS_INACTIVE) {
				if ("Inactive".equalsIgnoreCase(isActiveOrInactiveTopics)) {
					modifyForumService.inactiveForumTopic(forum.getId(),
							topicName);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			//Always remember transfer all the forums to page for displaying
			List<Forum> list = modifyForumService.getAllForums();
			request.setAttribute("forumList", list);
			request.setAttribute("failed", "Modified failed!");
			errStatus = 1;
			errMessage = e.getMessage();
			JSONObject jo = new JSONObject();
			jo.put("error", errMessage);
			errors.add(jo);
		}
		//If no error happens, update forum with new information
		//Note:forum is got from JSonObject which is transfered from page
		if (errStatus != 1) {
			modifyForumService.updateForum(forum);
			oldForumName = forum.getName();
		}
		// Print JSONObject to request, used for displaying on page
		try {
			out = response.getWriter();
			JSONObject jso = new JSONObject();
			jso.put("forumId", forum.getId());
			jso.put("forumName", forum.getName().trim());
			jso.put("description", forum.getDescription().trim());
			jso.put("active", forum.getStatus());
			if (errStatus == 0) {
				//
				jsonObject.put("notice", "Saved Successfully!");
			} else {
				jsonObject.put("notice", "");
			}
			jsonObject.put("status", errStatus);
			//Also put forum info(here is "jso") into jsonObject
			jsonObject.put("forum", jso);
			//Carry the error messages
			jsonObject.put("errors", errors);
			//Print modify result with all the data to the request
			out.print(jsonObject);
			out.flush();
			out.close();
			return null;
		} catch (Exception exc) {
			exc.printStackTrace();
			return null;
		}
	}

	// ModifyFor
	public ActionForward initModifyForum(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) {

		String jsonString = CommonMethods.readJSONRequest(request);
		JSONObject jot = JSONObject.fromObject(jsonString);
		oldForumName = jot.getString("forumName");
		return null;
	}

	// Sort Forum List
	public List<Forum> sortForumList(String sortType, String sortOrder,
			List<Forum> list) {

		// Compare Forum By Forum Name
		Comparator<Forum> compareByForumName = new Comparator<Forum>() {
			public int compare(Forum f1, Forum f2) {
				return f1.getName().compareTo(f2.getName());
			}
		};

		// Compare Forum By Forum Status
		Comparator<Forum> compareByForumStatus = new Comparator<Forum>() {
			public int compare(Forum f1, Forum f2) {
				// return g1.getStatus().compareTo(g2.getStatus());
				if (!QueryHelper.isNullOrEmpty(f1.getStatus())
						&& !QueryHelper.isNullOrEmpty(f2.getStatus())) {
					if (f1.getStatus() < f2.getStatus()) {
						return -1;
					}
					if (f1.getStatus() > f2.getStatus()) {
						return 1;
					}
				}
				return 0;
			}
		};

		// Compare Forum By Forum Desc
		Comparator<Forum> compareByForumDesc = new Comparator<Forum>() {
			public int compare(Forum f1, Forum f2) {
				return f1.getDescription().compareTo(f2.getDescription());
			}
		};

		if (null == sortType) {
			Collections.sort(list, compareByForumName);
		}
		if ("name".equals(sortType)) {
			Collections.sort(list, compareByForumName);
			if ("desc".equals(sortOrder)) {
				Collections.reverse(list);
			}
		}
		if ("status".equals(sortType)) {
			Collections.sort(list, compareByForumStatus);
			if ("desc".equals(sortOrder)) {
				Collections.reverse(list);
			}
		}
		if ("desc".equals(sortType)) {
			Collections.sort(list, compareByForumDesc);
			if ("desc".equals(sortOrder)) {
				Collections.reverse(list);
			}
		}
		return list;
	}

	// List all Forums when first enter the "modifyForum.jsp" page
	public ActionForward listForum(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		// get query criteria from ActionForm
		String forumNameQuery = ((ModifyForumForm) form).getForumNameQuery();
		Integer forumActiveQuery = ((ModifyForumForm) form)
				.getForumActiveQuery();
		// get sort parameters(sortType & sortOrder)
		String sortType = ((ModifyForumForm) form).getSortType();
		String sortOrder = ((ModifyForumForm) form).getSortOrder();
		
		//This list stored all the forums queried form database
		List<Forum> list;
		// if forum status not decided, query forum depending on just forum
		// name.
		if (null == forumActiveQuery || 99 == forumActiveQuery) {
			list = modifyForumService.queryForum(forumNameQuery, null);
			forumActiveQuery = 99;
			// else query depending on both forum name and status
		} else {
			list = modifyForumService.queryForum(forumNameQuery,
					forumActiveQuery);
		}

		sortForumList(sortType, sortOrder, list);
		if (null == sortType) {
			sortType = "name";
			sortOrder = "asce";
		}
		//Total row number depends on the forum returned from server
		int totalRows = list.size();
		//Initial current page at page 1
		int nowPage = 1;
		//Get page numbers 
		int totalPage = getTotalPage(pageSize, totalRows);

		List<Forum> data = new ArrayList<Forum>();
		/**
		 * Add associated forums to current page
		 */
		if (totalRows >= nowPage * pageSize) {
			for (int i = nowPage - 1; i < nowPage * pageSize; i++) {
				data.add(list.get(i));
			}
		} else {
			for (int i = nowPage - 1; i < totalRows; i++) {
				data.add(list.get(i));
			}
		}
		//Set all the query conditions to request because we still need them on page 
		request.setAttribute("forumNameQuery", forumNameQuery);
		request.setAttribute("forumActiveQuery", forumActiveQuery);
		request.setAttribute("sortType", sortType);
		request.setAttribute("sortOrder", sortOrder);
		request.setAttribute("totalPage", nowPage + "/" + totalPage);
		request.setAttribute("nowPage", nowPage);
		//Return forums on current page back
		request.setAttribute("forumList", data);
		request.setAttribute("totalPageNum", totalPage);
		request.setAttribute("statusMap", getStatusMap());
		return mapping.findForward("succ");
	}

	public HashMap<String, String> getStatusMap() {
		HashMap<String, String> map = new HashMap<String, String>();
		map.put("0", "Yes");
		map.put("1", "No");
		return map;
	}

	// Go to Next Page
	public ActionForward goToNextPage(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		String forumNameQuery = ((ModifyForumForm) form).getForumNameQuery();
		Integer forumActiveQuery = ((ModifyForumForm) form)
				.getForumActiveQuery();
		String sortType = ((ModifyForumForm) form).getSortType();
		String sortOrder = ((ModifyForumForm) form).getSortOrder();
		List<Forum> list;
		if (forumActiveQuery == 99 || null == forumActiveQuery) {
			list = modifyForumService.queryForum(forumNameQuery, null);
		} else {
			list = modifyForumService.queryForum(forumNameQuery,
					forumActiveQuery);
		}

		sortForumList(sortType, sortOrder, list);
		int totalRows = list.size();

		ModifyForumForm gmf = (ModifyForumForm) form;
		int nowPage = gmf.getNowPage();
		int totalPage = getTotalPage(pageSize, totalRows);

		List<Forum> data = new ArrayList<Forum>();
		if (totalRows > (nowPage + 1) * pageSize) {
			for (int i = nowPage * pageSize; i < (nowPage + 1) * pageSize; i++) {
				data.add(list.get(i));
			}
		} else {
			for (int i = nowPage * pageSize; i < totalRows; i++) {
				data.add(list.get(i));
			}
		}
		nowPage = nowPage + 1;
		request.setAttribute("forumNameQuery", forumNameQuery);
		request.setAttribute("forumActiveQuery", forumActiveQuery);
		request.setAttribute("sortType", sortType);
		request.setAttribute("sortOrder", sortOrder);
		request.setAttribute("totalPage", nowPage + "/" + totalPage);
		request.setAttribute("nowPage", nowPage);
		request.setAttribute("forumList", data);
		request.setAttribute("totalPageNum", totalPage);
		request.setAttribute("statusMap", getStatusMap());
		return mapping.findForward("succ");
	}

	// Go to Previous Page
	public ActionForward goToPreviousPage(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) {
		String forumNameQuery = ((ModifyForumForm) form).getForumNameQuery();
		Integer forumActiveQuery = ((ModifyForumForm) form)
				.getForumActiveQuery();
		String sortType = ((ModifyForumForm) form).getSortType();
		String sortOrder = ((ModifyForumForm) form).getSortOrder();
		List<Forum> list;
		if (forumActiveQuery == 99 || null == forumActiveQuery) {
			list = modifyForumService.queryForum(forumNameQuery, null);
		} else {
			list = modifyForumService.queryForum(forumNameQuery,
					forumActiveQuery);
		}

		sortForumList(sortType, sortOrder, list);
		int totalRows = list.size();
		ModifyForumForm gmf = (ModifyForumForm) form;
		int nowPage = gmf.getNowPage();
		int totalPage = getTotalPage(pageSize, totalRows);

		List<Forum> data = new ArrayList<Forum>();
		if (nowPage - 2 >= 0) {
			for (int i = (nowPage - 2) * pageSize; i < (nowPage - 1) * pageSize; i++) {
				data.add(list.get(i));
			}
		}

		nowPage = nowPage - 1;
		request.setAttribute("forumNameQuery", forumNameQuery);
		request.setAttribute("forumActiveQuery", forumActiveQuery);
		request.setAttribute("sortType", sortType);
		request.setAttribute("sortOrder", sortOrder);
		request.setAttribute("totalPage", nowPage + "/" + totalPage);
		request.setAttribute("nowPage", nowPage);
		request.setAttribute("forumList", data);
		request.setAttribute("totalPageNum", totalPage);
		request.setAttribute("statusMap", getStatusMap());
		return mapping.findForward("succ");
	}

	// Go to Target Page
	public ActionForward goToTargetPage(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		String forumNameQuery = ((ModifyForumForm) form).getForumNameQuery();
		Integer forumActiveQuery = ((ModifyForumForm) form)
				.getForumActiveQuery();
		String sortType = ((ModifyForumForm) form).getSortType();
		String sortOrder = ((ModifyForumForm) form).getSortOrder();
		List<Forum> list;
		if (forumActiveQuery == 99 || null == forumActiveQuery) {
			list = modifyForumService.queryForum(forumNameQuery, null);
		} else {
			list = modifyForumService.queryForum(forumNameQuery,
					forumActiveQuery);
		}
		sortForumList(sortType, sortOrder, list);
		int totalRows = list.size();
		ModifyForumForm gmf = (ModifyForumForm) form;
		//get target page number from ActionForm
		int nowPage = gmf.getTargetPage();
		int totalPage = getTotalPage(pageSize, totalRows);
		List<Forum> data = new ArrayList<Forum>();

		if (nowPage > 0 && nowPage <= totalPage) {
			//Call "getTargetPageForums(,,)" method to get forums displayed on target page
			data = getTargetPageForums(list, nowPage, totalRows);
		}

		request.setAttribute("forumNameQuery", forumNameQuery);
		request.setAttribute("forumActiveQuery", forumActiveQuery);
		request.setAttribute("sortType", sortType);
		request.setAttribute("sortOrder", sortOrder);
		request.setAttribute("totalPage", nowPage + "/" + totalPage);
		request.setAttribute("nowPage", nowPage);
		request.setAttribute("forumList", data);
		request.setAttribute("totalPageNum", totalPage);
		request.setAttribute("statusMap", getStatusMap());
		return mapping.findForward("succ");
	}

	// Get Forums on target page, This method is much useful
	public List<Forum> getTargetPageForums(List<Forum> list, int targetNum,
			int totalNum) {
		List<Forum> data = new ArrayList<Forum>();
		if (targetNum * pageSize <= totalNum) {
			for (int i = (targetNum - 1) * pageSize; i < (targetNum * pageSize); i++) {
				data.add(list.get(i));
			}
		} else {
			for (int i = (targetNum - 1) * pageSize; i < totalNum; i++) {
				data.add(list.get(i));
			}
		}
		return data;
	}

	public int getTotalPage(int pageSize, int totalRows) {
		int totalPage;
		if (totalRows % pageSize > 0) {
			totalPage = totalRows / pageSize + 1;
		} else {
			totalPage = totalRows / pageSize;
		}
		return totalPage;
	}

	// Query Forum
	public ActionForward queryForum(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		String forumNameQuery = ((ModifyForumForm) form).getForumNameQuery();
		Integer forumActiveQuery = ((ModifyForumForm) form)
				.getForumActiveQuery();
		if (forumActiveQuery == 99) {
			forumActiveQuery = null;
		}
		List<Forum> list = modifyForumService.queryForum(forumNameQuery,
				forumActiveQuery);
		Collections.sort(list);
		return mapping.findForward("succ");
	}

	// Delete Forum
	// will not be used
	public ActionForward delete(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		try {
			@SuppressWarnings("unused")
			ModifyForumForm modifyForumForm = (ModifyForumForm) form;
			// ((Object)
			// modifyGroupService).deleteGroupbyId(modifyGroupForm.getGroupId());
			List<Forum> forumList = modifyForumService.getAllForums();
			request.setAttribute("forumList", forumList);
			request.setAttribute("Success", "Deleted Successfully!");
			return mapping.findForward("succ");
		} catch (Exception e) {
			e.printStackTrace();
			request.setAttribute("Failed", "Deleted Failed!");
			return mapping.findForward("failed");
		}
	}

	// serialize a Forum from JSONObject
	public Forum serializeForum(JSONObject jo) {
		Forum forum = new Forum();
		forum.setId(jo.getInt("id"));
		Forum oldForum = modifyForumService.getForumById(jo.getInt("id"));
		forum.setTopics(oldForum.getTopics());
		forum.setDescription(jo.getString("description"));
		forum.setName(jo.getString("forumName"));
		forum.setStatus(jo.getInt("status"));
		return forum;
	}

	// serialize a Forum from Form
	public Forum serializeForum(ModifyForumForm mff) {
		Forum forum = new Forum();
		forum.setDescription(mff.getForumDesc());
		forum.setName(mff.getForumName());
		forum.setId(mff.getForumId());
		return forum;
	}
}
